package com.feib.soeasy.dao.hibernate;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.feib.soeasy.dao.UserDao;
import com.feib.soeasy.model.Group;
import com.feib.soeasy.model.Role;
import com.feib.soeasy.model.User;
import com.feib.soeasy.pagination.PaginatedList;

/**
 * @title (#)UserHibernateDao.java<br>
 * @description <br>
 * @author Jimmy Liu<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/11/14 create by Jimmy Liu<br>
 */
@Repository("userDao")
public class UserHibernateDao extends BaseHibernateDao<User, Long> implements UserDao
{

    /*
     * (non-Javadoc)
     * 
     * @see com.feib.soeasy.dao.UserDao#findByUerIdGroupNo(java.lang.String,
     * java.lang.String)
     */
    @Override
    public User findByUerIdGroupNo(String userId, String groupNo)
    {

        if(StringUtils.isEmpty(userId) || StringUtils.isEmpty(groupNo))
            return null;

        DetachedCriteria criteria = DetachedCriteria.forClass(this.getPersistentClass());
        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);

        criteria.add(Restrictions.eq("userId", userId));

        DetachedCriteria detachedCriteria = criteria.createCriteria("group");
        detachedCriteria.add(Restrictions.eq("groupNo", groupNo));

        @SuppressWarnings("unchecked")
        List<User> users = this.getHibernateTemplate().findByCriteria(criteria);

        return DataAccessUtils.singleResult(users);
    }

    @Override
    public PaginatedList<User> findByUerIdUserNameGroupNo(	String userId,
                    String userName,
                    String groupNo,
                    ROLE_CONSTRAINT role_constraint,
                    String roleNo,
                    PaginatedList<User> paginationConfig)
                    {

        logger.debug("================queryPaginationByUerIdGroupNo=====================");
        PaginatedList<User> result = new PaginatedList<User>();
        result.setPageSize(paginationConfig.getPageSize());
        result.setPageNumber(paginationConfig.getPageNumber());
        result.setSortCriterion(paginationConfig.getSortCriterion());

        DetachedCriteria criteria = DetachedCriteria.forClass(this.getPersistentClass());
        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);

        if(userId != null && !userId.equals(""))
        {
            criteria.add(Restrictions.eq("userId", userId));
        }

        if(userName != null && !userName.equals(""))
        {
            criteria.add(Restrictions.eq("userName", userName));

        }
        DetachedCriteria detachedCriteria = criteria.createCriteria("group");
        if(groupNo != null && !groupNo.equals(""))
        {
            detachedCriteria.add(Restrictions.eq("groupNo", groupNo));
        }

        result.setFullListSize(countByDetachedCriteria(criteria));
        logger.debug(	"================result size:{}=====================",
                        result.getFullListSize());
        // 筆數大於0
        if(0 < result.getFullListSize())
        {
            criteria = DetachedCriteria.forClass(this.getPersistentClass());
            criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);
            if(userId != null && !userId.equals(""))
            {
                criteria.add(Restrictions.eq("userId", userId));
            }

            if(userName != null && !userName.equals(""))
            {
                criteria.add(Restrictions.eq("userName", userName));

            }
            detachedCriteria = criteria.createCriteria("group");
            if(groupNo != null && !groupNo.equals(""))
            {
                detachedCriteria.add(Restrictions.eq("groupNo", groupNo));
            }

            // 排序
            if(null != paginationConfig.getSortCriterion())
            {
                // 由小到大
                if(PaginatedList.SORT_DIRECTION_ASC == paginationConfig.getSortDirection())
                {
                    criteria.addOrder(Order.asc(paginationConfig.getSortCriterion()));
                }
                else
                    // 由大到小
                {
                    criteria.addOrder(Order.asc(paginationConfig.getSortCriterion()));
                }
            }

            int maxResults = result.getPageSize(); // the maximum number of
            // results
            int firstResult = result.getFirstIndexForCurrentPage(); // the first
            // result to
            // retrieve,
            // numbered
            // from 0
            @SuppressWarnings("unchecked")
            List<User> users = this.getHibernateTemplate().findByCriteria(	criteria,
                            firstResult,
                            maxResults);

            if(roleNo != null && !roleNo.equals(""))
            {

                List<User> role_constraint_User = filterByRoleConstarint(	users,
                                roleNo,
                                role_constraint);

                result.setPaginatedList(role_constraint_User);
            }
            else
            {
                result.setPaginatedList(users);
            }
        }

        return result;
                    }

    private List<User> filterByRoleConstarint(	List<User> users,
                    String roleNo,
                    ROLE_CONSTRAINT role_constraint)
                    {
        List<User> role_constraint_User = new ArrayList<User>();

        if(role_constraint.equals(ROLE_CONSTRAINT.OnlyThisRole))
        {
            for(int i = 0; i < users.size(); i++)
            {
                Iterator<Role> iterator = users.get(i).getRoles().iterator();

                while(iterator.hasNext())
                {
                    Role role = iterator.next();

                    if(role.getRoleNo().equals(roleNo))
                    {
                        role_constraint_User.add(users.get(i));
                        break;
                    }
                }

            }
        }
        else if(role_constraint.equals(ROLE_CONSTRAINT.WithoutThisRole))
        {

            for(int i = 0; i < users.size(); i++)
            {
                Iterator<Role> iterator = users.get(i).getRoles().iterator();

                while(iterator.hasNext())
                {
                    Role role = iterator.next();

                    if(!role.getRoleNo().equals(roleNo))
                    {
                        role_constraint_User.add(users.get(i));
                    }
                }

            }
        }
        else
        {
            role_constraint_User = users;
        }

        return role_constraint_User;

                    }

    @Override
    public List<User> findByGroupNo(String groupNo)
    {
        if(StringUtils.isEmpty(groupNo))
            return null;

        DetachedCriteria criteria = DetachedCriteria.forClass(this.getPersistentClass());
        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);

        DetachedCriteria detachedCriteria = criteria.createCriteria("group");
        detachedCriteria.add(Restrictions.eq("groupNo", groupNo));

        @SuppressWarnings("unchecked")
        List<User> users = this.getHibernateTemplate().findByCriteria(criteria);

        return users;
    }

    /* (non-Javadoc)
     * @see com.feib.soeasy.dao.UserDao#findUserEmailByGroupMenuId(com.feib.soeasy.model.Group, java.lang.String)
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<String> findUserEmailByGroupMenuId(Group group, String menuId) {
        StringBuffer queryString = new StringBuffer();

        queryString.append("select user.userEmail from User user inner join user.roles role inner join role.menuItems menuItem ");
        queryString.append("where user.group = :group ");
        queryString.append("and menuItem.menuId = :menuId ");
        Query query = this.getSession().createQuery(queryString.toString());
        query.setParameter("group", group);
        query.setParameter("menuId", menuId);
        return query.list();
    }
    
    /**
     * 查詢帳單業者的使用者資料
     * 
     * @param groupNo 業者代號，一定要有，完全比對
     * @param userId 使用者帳號
     * @param userName 使用者名稱
     * @param paginationConfig 分頁條件
     * @return
     */
    @SuppressWarnings("unchecked")
    public PaginatedList<User> queryPaginationUsers(String groupNo, String userId, String userName,PaginatedList<User> paginationConfig)
    {
        Assert.notNull(groupNo, "業者代號不可為NULL");
        PaginatedList<User> result = new PaginatedList<User>()
        ;result.setPageSize(paginationConfig.getPageSize());
        result.setPageNumber(paginationConfig.getPageNumber());
        result.setSortCriterion(paginationConfig.getSortCriterion());
        result.setSortDirection(paginationConfig.getSortDirection());
        
        result.setFullListSize(super.countByDetachedCriteria(createCriteriaByUerIdUserNameGroupNo(groupNo, userId, userName)));
        

        // 筆數大於0
        if (0 < result.getFullListSize())
        {
            DetachedCriteria criteria = createCriteriaByUerIdUserNameGroupNo(groupNo, userId, userName);

            //排序
            if (null != paginationConfig.getSortCriterion())
            {
                // 由小到大
                if (PaginatedList.SORT_DIRECTION_ASC == paginationConfig.getSortDirection())
                {
                    criteria.addOrder(Order.asc(paginationConfig.getSortCriterion()));
                }
                else // 由大到小
                {
                    criteria.addOrder(Order.asc(paginationConfig.getSortCriterion()));
                }
            }


            int maxResults = result.getPageSize(); //the maximum number of results
            int firstResult = result.getFirstIndexForCurrentPage();  //the first result to retrieve, numbered from 0
            result.setPaginatedList(this.getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults));
        }
        
        return result;
    }
    

    /**
     * @param groupNo
     * @param userId
     * @param userName
     * @return
     */
    private DetachedCriteria createCriteriaByUerIdUserNameGroupNo(String groupNo, String userId, String userName) {
        
        Assert.notNull(groupNo, "業者代號不可為NULL");
        
        DetachedCriteria criteria = DetachedCriteria.forClass(this.getPersistentClass());
        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);
        
        if (StringUtils.isNotEmpty(userId))
            criteria.add(Restrictions.like("userId", userId+"%"));
        
        if (StringUtils.isNotEmpty(userName))
            criteria.add(Restrictions.like("userName", userName+"%"));
        
        DetachedCriteria groupCriteria = criteria.createCriteria("group");
        groupCriteria.add(Restrictions.eq("groupNo", groupNo));
        
        return criteria;
    }

    /**
     * 以業者代號查詢ADMINISTRATOR的USER
     * @param groupNo 業者代號，一定要有
     * @param paginationConfig 分頁條件
     * @return
     */
    @SuppressWarnings("unchecked")
    public PaginatedList<User> queryPaginationForAdministratorByGroupNo(String groupNo, PaginatedList<User> paginationConfig)
    {
        Assert.notNull(groupNo, "業者代號不可為NULL");
        PaginatedList<User> result = new PaginatedList<User>()
        ;result.setPageSize(paginationConfig.getPageSize());
        result.setPageNumber(paginationConfig.getPageNumber());
        result.setSortCriterion(paginationConfig.getSortCriterion());
        result.setSortDirection(paginationConfig.getSortDirection());
        
        result.setFullListSize(super.countByDetachedCriteria(createCriteriaForAdministratorByGroupNo(groupNo)));
        

        // 筆數大於0
        if (0 < result.getFullListSize())
        {
            DetachedCriteria criteria = createCriteriaForAdministratorByGroupNo(groupNo);

            //排序
            if (null != paginationConfig.getSortCriterion())
            {
                // 由小到大
                if (PaginatedList.SORT_DIRECTION_ASC == paginationConfig.getSortDirection())
                {
                    criteria.addOrder(Order.asc(paginationConfig.getSortCriterion()));
                }
                else // 由大到小
                {
                    criteria.addOrder(Order.asc(paginationConfig.getSortCriterion()));
                }
            }


            int maxResults = result.getPageSize(); //the maximum number of results
            int firstResult = result.getFirstIndexForCurrentPage();  //the first result to retrieve, numbered from 0
            result.setPaginatedList(this.getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults));
        }
        
        return result;
    }
    
    protected DetachedCriteria createCriteriaForAdministratorByGroupNo(String groupNo)
    {
        Assert.notNull(groupNo, "業者代號不可為NULL");
        
        DetachedCriteria criteria = DetachedCriteria.forClass(this.getPersistentClass());
        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);
        
        // 限定 ADMIN
        criteria.add(Restrictions.eq("userId", "admin"));
        
        DetachedCriteria groupCriteria = criteria.createCriteria("group");
        groupCriteria.add(Restrictions.like("groupNo", groupNo+"%"));
        
        // 只列出 系統管理者的使用者
        DetachedCriteria roleCriteria = criteria.createCriteria("roles");
        roleCriteria.add(Restrictions.eq("roleNo", "ADMINISTRATOR"));
        
        return criteria;
        
    }

    /* (non-Javadoc)
     * @see com.feib.soeasy.dao.UserDao#countUserByGroupExcludeAdmin(com.feib.soeasy.model.Group)
     */
    @Override
    public int countUserByGroupExcludeAdmin(Group group) {

        DetachedCriteria criteria = DetachedCriteria.forClass(this.getPersistentClass());
        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);       

        
        // 限定不是 ADMIN
        criteria.add(Restrictions.not(Restrictions.eq("userId", "admin")));

        DetachedCriteria detachedCriteria = criteria.createCriteria("group");
        detachedCriteria.add(Restrictions.idEq(group.getGroupPk()));

        return countByDetachedCriteria(criteria);
    }

    /* (non-Javadoc)
     * @see com.feib.soeasy.dao.UserDao#deleteByGroup(com.feib.soeasy.model.Group)
     */
    @SuppressWarnings("unchecked")
    @Override
    public void deleteByGroup(Group group) {
        StringBuffer hql = new StringBuffer();
        hql.append("from User ");
        hql.append("where group = :group ");
        Query query = getSession().createQuery(hql.toString());
        query.setParameter("group", group);
        List<User> users = query.list();
        for(User u: users)
        {
            hql = new StringBuffer();
            hql.append("delete UserLoginControl ");
            hql.append("where user = :user ");
            query = getSession().createQuery(hql.toString());
            query.setParameter("user", u);
            query.executeUpdate();
            
            this.delete(u);
        }
    }
}
